// Copyright 2021 ETH Zurich and University of Bologna.
// Solderpad Hardware License, Version 0.51, see LICENSE for details.
// SPDX-License-Identifier: SHL-0.51
//
// Author: Matheus Cavalcante <matheusd@iis.ee.ethz.ch>
//         Basile Bougenot <bbougenot@student.ethz.ch>
//         Matteo Perotti <mperotti@iis.ee.ethz.ch>

#include "vector_macros.h"
#include "float_macros.h"

// Simple random test with similar values
void TEST_CASE1(void) {
  VSET(16, e16, m1);
  //               52.7812,  74.1875,  0.3564,  97.5000,  7.8477,  53.2188, -26.4688, -48.1250, -32.9688,  7.8750, -38.4375,  51.5625,  46.2188, -75.1875,  23.5625, -77.8125
  VLOAD_16(v2,     0x5299,  0x54a3,  0x35b4,  0x5618,  0x47d9,  0x52a7,  0xce9e,  0xd204,  0xd01f,  0x47e0,  0xd0ce,  0x5272,  0x51c7,  0xd4b3,  0x4de4,  0xd4dd);
  //               49.6875,  28.5312,  13.4766, -90.5625,  58.0000, -63.8125,  49.0625,  0.3325,  30.8906,  11.2266, -93.9375, -54.6875,  61.7500,  38.3438,  95.8125,  10.0938
  VLOAD_16(v6,     0x5236,  0x4f22,  0x4abd,  0xd5a9,  0x5340,  0xd3fa,  0x5222,  0x3552,  0x4fb9,  0x499d,  0xd5df,  0xd2d6,  0x53b8,  0x50cb,  0x55fd,  0x490c);
  //              -83.87223053, -48.34465408,  70.48658752, -1.26614821, -24.13150024, -65.13838196,  0.84671319,  34.34510040,  72.80049896, -86.23424530,  25.52654839, -68.44364929,  9.81109142, -85.20966339, -81.00300598,  16.25512505
  VLOAD_32(v4,     0xc2a7be95,  0xc24160ed,  0x428cf922,  0xbfa21125,  0xc1c10d50,  0xc28246da,  0x3f58c232,  0x42096162,  0x429199db,  0xc2ac77ef,  0x41cc365f,  0xc288e326,  0x411cfa3b,  0xc2aa6b59,  0xc2a2018a,  0x41820a7f);
  asm volatile("vfwmacc.vv v4, v2, v6");
  //               2538.69604492,  2068.31738281,  75.29024506, -8831.11035156,  431.03256226, -3461.15991211, -1297.77636719,  18.34259796, -945.62481689,  2.17493439,  3636.24926758, -2888.26782227,  2863.81884766, -2968.18041992,  2176.57910156, -769.16479492
  VCMP_U32(1, v4,  0x451eab23,  0x45014514,  0x4296949b,  0xc609fc71,  0x43d7842b,  0xc558528f,  0xc4a238d8,  0x4192bda4,  0xc46c67fd,  0x400b3220,  0x456343fd,  0xc5348449,  0x4532fd1a,  0xc53982e3,  0x45080944,  0xc4404a8c);

  VSET(16, e32, m1);
  //              -3306.98510742, -33314.88281250,  64578.31250000,  11648.08203125, -92704.16406250,  33998.11328125,  23406.90429688,  44169.36718750, -1206.53601074,  4568.00048828, -89687.13281250,  47865.25781250, -72205.21875000,  40772.06640625,  95904.72656250,  96043.19531250
  VLOAD_32(v2,     0xc54eafc3,  0xc70222e2,  0x477c4250,  0x46360054,  0xc7b51015,  0x4704ce1d,  0x46b6ddcf,  0x472c895e,  0xc496d127,  0x458ec001,  0xc7af2b91,  0x473af942,  0xc78d069c,  0x471f4411,  0x47bb505d,  0x47bb9599);
  //              -52385.05468750, -31301.09960938,  1862.59667969,  86344.56250000,  9560.06835938, -93766.92187500, -68756.87500000,  42627.23046875, -89604.89062500, -47420.98437500, -40235.07421875,  44342.39453125,  90261.61718750,  76035.55468750, -92912.59375000,  40474.20703125
  VLOAD_32(v6,     0xc74ca10e,  0xc6f48a33,  0x44e8d318,  0x47a8a448,  0x46156046,  0xc7b72376,  0xc7864a70,  0x4726833b,  0xc7af0272,  0xc7393cfc,  0xc71d2b13,  0x472d3665,  0x47b04acf,  0x479481c7,  0xc7b5784c,  0x471e1a35);
  //              -10044.0368110413110116,  13040.9349537673260784,  88916.1136409099854063,  79168.4367756713472772,  21611.0950133731239475, -26455.6752808090968756,  5979.6755084589240141, -99733.4556307629245566,  85141.1192070578690618, -87838.0155233480472816,  53604.5772563865466509, -30101.3490022116457112,  80638.7360704737366177, -75019.8948306038219016,  63887.5576457676361315,  1225.3713199536578031
  VLOAD_64(v4,     0xc0c39e04b6396548,  0x40c97877ac90a6f8,  0x40f5b541d179217e,  0x40f35406fd087c82,  0x40d51ac614b2f890,  0xc0d9d5eb37ccffac,  0x40b75bacee1f5340,  0xc0f859574a437b9d,  0x40f4c951e845a8f0,  0xc0f571e03f956903,  0x40ea2c9278e262b4,  0xc0dd6556560d5f50,  0x40f3afebc6f1d544,  0xc0f250be5139e52e,  0x40ef31f1d83befd8,  0x4093257c3b4c4540);
  asm volatile("vfwmacc.vv v4, v2, v6");
  //               173226551.6662319302558899,  1042805506.3236714601516724,  120372266.5559626817703247,  1005827715.3891682624816895, -886236534.5412018299102783, -3187924887.6156492233276367, -1609379613.2016887664794922,  1882718061.3047757148742676,  108196668.3968845903873444, -216706917.7953008711338043,  3608622049.7550821304321289,  2122430044.9128692150115967, -6517279175.0161266326904297,  3100051665.0599727630615234, -8910693010.2487506866455078,  3887273396.3922243118286133
  VCMP_U64(2, v4,  0x41a4a6746f551c5a,  0x41cf13f981296e11,  0x419cb2f0aa394e48,  0x41cdf9db41b1d044,  0xc1ca6972bb45461a,  0xc1e7c07bf2f3b366,  0xc1d7fb4bc74ce878,  0x41dc0dffdb538172,  0x4199cbccf19668ea,  0xc1a9d55ecb9731ad,  0x41eae2e67c3829a2,  0x41dfa06d973a6c73,  0xc1f8475c9c70420e,  0x41e718e11a21eb4c,  0xc20098f31491fd71,  0x41ecf662b68c8d1a);
};

// Simple random test with similar values (masked)
// The numbers are the same of TEST_CASE1
void TEST_CASE2(void) {
  VSET(16, e16, m1);
  //               52.7812,  74.1875,  0.3564,  97.5000,  7.8477,  53.2188, -26.4688, -48.1250, -32.9688,  7.8750, -38.4375,  51.5625,  46.2188, -75.1875,  23.5625, -77.8125
  VLOAD_16(v2,     0x5299,  0x54a3,  0x35b4,  0x5618,  0x47d9,  0x52a7,  0xce9e,  0xd204,  0xd01f,  0x47e0,  0xd0ce,  0x5272,  0x51c7,  0xd4b3,  0x4de4,  0xd4dd);
  //               49.6875,  28.5312,  13.4766, -90.5625,  58.0000, -63.8125,  49.0625,  0.3325,  30.8906,  11.2266, -93.9375, -54.6875,  61.7500,  38.3438,  95.8125,  10.0938
  VLOAD_16(v6,     0x5236,  0x4f22,  0x4abd,  0xd5a9,  0x5340,  0xd3fa,  0x5222,  0x3552,  0x4fb9,  0x499d,  0xd5df,  0xd2d6,  0x53b8,  0x50cb,  0x55fd,  0x490c);
  VLOAD_8(v0, 0xAA, 0xAA);
  //              -83.87223053, -48.34465408,  70.48658752, -1.26614821, -24.13150024, -65.13838196,  0.84671319,  34.34510040,  72.80049896, -86.23424530,  25.52654839, -68.44364929,  9.81109142, -85.20966339, -81.00300598,  16.25512505
  VLOAD_32(v4,     0xc2a7be95,  0xc24160ed,  0x428cf922,  0xbfa21125,  0xc1c10d50,  0xc28246da,  0x3f58c232,  0x42096162,  0x429199db,  0xc2ac77ef,  0x41cc365f,  0xc288e326,  0x411cfa3b,  0xc2aa6b59,  0xc2a2018a,  0x41820a7f);
  asm volatile("vfwmacc.vv v4, v2, v6, v0.t");
  //              -83.87223053,  2068.31738281,  70.48658752, -8831.11035156, -24.13150024, -3461.15991211,  0.84671319,  18.34259796,  72.80049896,  2.17493439,  25.52654839, -2888.26782227,  9.81109142, -2968.18041992, -81.00300598, -769.16479492
  VCMP_U32(3, v4,  0xc2a7be95,  0x45014514,  0x428cf922,  0xc609fc71,  0xc1c10d50,  0xc558528f,  0x3f58c232,  0x4192bda4,  0x429199db,  0x400b3220,  0x41cc365f,  0xc5348449,  0x411cfa3b,  0xc53982e3,  0xc2a2018a,  0xc4404a8c);

  VSET(16, e32, m1);
  //              -3306.98510742, -33314.88281250,  64578.31250000,  11648.08203125, -92704.16406250,  33998.11328125,  23406.90429688,  44169.36718750, -1206.53601074,  4568.00048828, -89687.13281250,  47865.25781250, -72205.21875000,  40772.06640625,  95904.72656250,  96043.19531250
  VLOAD_32(v2,     0xc54eafc3,  0xc70222e2,  0x477c4250,  0x46360054,  0xc7b51015,  0x4704ce1d,  0x46b6ddcf,  0x472c895e,  0xc496d127,  0x458ec001,  0xc7af2b91,  0x473af942,  0xc78d069c,  0x471f4411,  0x47bb505d,  0x47bb9599);
  //              -52385.05468750, -31301.09960938,  1862.59667969,  86344.56250000,  9560.06835938, -93766.92187500, -68756.87500000,  42627.23046875, -89604.89062500, -47420.98437500, -40235.07421875,  44342.39453125,  90261.61718750,  76035.55468750, -92912.59375000,  40474.20703125
  VLOAD_32(v6,     0xc74ca10e,  0xc6f48a33,  0x44e8d318,  0x47a8a448,  0x46156046,  0xc7b72376,  0xc7864a70,  0x4726833b,  0xc7af0272,  0xc7393cfc,  0xc71d2b13,  0x472d3665,  0x47b04acf,  0x479481c7,  0xc7b5784c,  0x471e1a35);
  VLOAD_8(v0, 0xAA, 0xAA);
  //              -10044.0368110413110116,  13040.9349537673260784,  88916.1136409099854063,  79168.4367756713472772,  21611.0950133731239475, -26455.6752808090968756,  5979.6755084589240141, -99733.4556307629245566,  85141.1192070578690618, -87838.0155233480472816,  53604.5772563865466509, -30101.3490022116457112,  80638.7360704737366177, -75019.8948306038219016,  63887.5576457676361315,  1225.3713199536578031
  VLOAD_64(v4,     0xc0c39e04b6396548,  0x40c97877ac90a6f8,  0x40f5b541d179217e,  0x40f35406fd087c82,  0x40d51ac614b2f890,  0xc0d9d5eb37ccffac,  0x40b75bacee1f5340,  0xc0f859574a437b9d,  0x40f4c951e845a8f0,  0xc0f571e03f956903,  0x40ea2c9278e262b4,  0xc0dd6556560d5f50,  0x40f3afebc6f1d544,  0xc0f250be5139e52e,  0x40ef31f1d83befd8,  0x4093257c3b4c4540);
  asm volatile("vfwmacc.vv v4, v2, v6, v0.t");
  //              -10044.0368110413110116,  1042805506.3236714601516724,  88916.1136409099854063,  1005827715.3891682624816895,  21611.0950133731239475, -3187924887.6156492233276367,  5979.6755084589240141,  1882718061.3047757148742676,  85141.1192070578690618, -216706917.7953008711338043,  53604.5772563865466509,  2122430044.9128692150115967,  80638.7360704737366177,  3100051665.0599727630615234,  63887.5576457676361315,  3887273396.3922243118286133
  VCMP_U64(4, v4,  0xc0c39e04b6396548,  0x41cf13f981296e11,  0x40f5b541d179217e,  0x41cdf9db41b1d044,  0x40d51ac614b2f890,  0xc1e7c07bf2f3b366,  0x40b75bacee1f5340,  0x41dc0dffdb538172,  0x40f4c951e845a8f0,  0xc1a9d55ecb9731ad,  0x40ea2c9278e262b4,  0x41dfa06d973a6c73,  0x40f3afebc6f1d544,  0x41e718e11a21eb4c,  0x40ef31f1d83befd8,  0x41ecf662b68c8d1a);
};

// Simple random test with similar values (vector-scalar)
void TEST_CASE3(void) {
  VSET(16, e16, m1);
  double dscalar_16;
  //              -15.3750,  11.9375, -31.7656,  27.0625,  3.0684,  71.2500,  63.2500, -95.6875, -62.0625, -27.7344,  55.5312, -62.1875, -42.1875, -95.3125,  27.1406, -16.9219
  VLOAD_16(v2,     0xcbb0,  0x49f8,  0xcff1,  0x4ec4,  0x4223,  0x5474,  0x53e8,  0xd5fb,  0xd3c2,  0xceef,  0x52f1,  0xd3c6,  0xd146,  0xd5f5,  0x4ec9,  0xcc3b);
  //                              32.2812
  BOX_HALF_IN_DOUBLE(dscalar_16,  0x5009);
  //              -70.22966003,  68.36327362, -69.75650787, -92.51078796, -53.56798553, -92.09814453,  92.33961487,  42.48206329,  99.15431976, -5.94871950, -55.92549133,  59.99367523, -45.05080032, -68.93397522,  55.13935089, -80.23659515
  VLOAD_32(v4,     0xc28c7596,  0x4288b9ff,  0xc28b8355,  0xc2b90586,  0xc256459e,  0xc2b83240,  0x42b8ade2,  0x4229eda2,  0x42c64f03,  0xc0be5be9,  0xc25fb3b4,  0x426ff986,  0xc2343405,  0xc289de32,  0x425c8eb2,  0xc2a07923);
  asm volatile("vfwmacc.vf v4, %[A], v2" :: [A] "f" (dscalar_16));
  //              -566.55389404,  453.72070312, -1095.19055176,  781.10052490,  45.48249054,  2207.94091797,  2134.12866211, -3046.42993164, -1904.30078125, -901.24902344,  1736.69262695, -1947.49658203, -1406.91601562, -3145.74072266,  931.27264404, -626.49584961
  VCMP_U32(5, v4,  0xc40da373,  0x43e2dc40,  0xc488e619,  0x4443466f,  0x4235ee12,  0x4509ff0e,  0x4505620f,  0xc53e66e1,  0xc4ee09a0,  0xc4614ff0,  0x44d9162a,  0xc4f36fe4,  0xc4afdd50,  0xc5449bda,  0x4468d173,  0xc41c9fbc);

  VSET(16, e32, m1);
  double dscalar_32;
  //              -260866.17187500, -221967.43750000, -907157.25000000,  754760.87500000, -585546.12500000,  260611.84375000, -768453.25000000, -117569.82812500, -469705.78125000,  775094.50000000,  533114.81250000, -798136.87500000,  66693.82812500,  246179.67187500,  728220.87500000, -749270.75000000
  VLOAD_32(v2,     0xc87ec08b,  0xc858c3dc,  0xc95d7954,  0x4938448e,  0xc90ef4a2,  0x487e80f6,  0xc93b9c54,  0xc7e5a0ea,  0xc8e55939,  0x493d3b68,  0x490227ad,  0xc942db8e,  0x478242ea,  0x487068eb,  0x4931c9ce,  0xc936ed6c);
  //                              -164832.20312500
  BOX_FLOAT_IN_DOUBLE(dscalar_32,  0xc820f80d);
  //              -730249.9193813583115116, -885955.2111547881504521, -739704.0702666083816439,  991252.9466537751723081, -543412.1947198503185064,  859135.3883249030914158,  862259.4763332824222744,  331294.3916525302920491,  936699.0835190876387060, -813722.4244660194963217, -602138.5575914122164249,  253718.7884360067546368,  7255.4825419568223879,  957493.0229552322998643, -446793.8022573012858629, -757660.7323241395642981
  VLOAD_64(v4,     0xc1264913d6b92745,  0xc12b09866c1c7afb,  0xc12692f023f9fc22,  0x412e4029e4afcdba,  0xc120956863b251fa,  0x412a37fec6d2858e,  0x412a5066f3e1f4bc,  0x41143879910d5c64,  0x412c95f62ac3038c,  0xc128d534d9539c30,  0xc12260351d7c9f20,  0x410ef8b64eb78980,  0x40bc577b87dea380,  0x412d386a0bc0c9c8,  0xc11b45273582f020,  0xc1271f3976f3308b);
  asm volatile("vfwmacc.vf v4, %[A], v2" :: [A] "f" (dscalar_32));
  //               42998415581.0217819213867188,  36586495789.9245910644531250,  149527988394.2461547851562500, -124407906605.8560791015625000,  96516314402.8619232177734375, -42956365230.3924331665039062,  126666704455.5427398681640625,  19379625085.2629890441894531,  77423575443.0703430175781250, -127761347787.4947814941406250, -87875091201.5038757324218750,  131558913220.3411712646484375, -10993283369.2012958526611328, -40577380186.7228927612304688, -120034697981.6674957275390625,  123503190798.8887634277343750
  VCMP_U64(6, v4,  0x422405cf81ba0b27,  0x422109733e5bd964,  0x4241684804551f82,  0xc23cf74a012ddb28,  0x423678d21522dca7,  0xc22400cc3b5cc8ed,  0x423d7dec86478af1,  0x42120c7671f50d4d,  0x423206ce01931202,  0xc23dbf2b74cb7eaa,  0xc23475c37b0180fe,  0x423ea185b4c45757,  0xc2047a0189499c41,  0xc222e5335eb5721f,  0xc23bf2a022fdaae1,  0x423cc15d230ee386);
};

// Simple random test with similar values (vector-scalar) (masked)
void TEST_CASE4(void) {
  VSET(16, e16, m1);
  double dscalar_16;
  //               -15.3750,  11.9375, -31.7656,  27.0625,  3.0684,  71.2500,  63.2500, -95.6875, -62.0625, -27.7344,  55.5312, -62.1875, -42.1875, -95.3125,  27.1406, -16.9219
  VLOAD_16(v2,      0xcbb0,  0x49f8,  0xcff1,  0x4ec4,  0x4223,  0x5474,  0x53e8,  0xd5fb,  0xd3c2,  0xceef,  0x52f1,  0xd3c6,  0xd146,  0xd5f5,  0x4ec9,  0xcc3b);
  //                              32.2812
  BOX_HALF_IN_DOUBLE(dscalar_16,  0x5009);
  VLOAD_8(v0, 0xAA, 0xAA);
  //               -70.22966003,  68.36327362, -69.75650787, -92.51078796, -53.56798553, -92.09814453,  92.33961487,  42.48206329,  99.15431976, -5.94871950, -55.92549133,  59.99367523, -45.05080032, -68.93397522,  55.13935089, -80.23659515
  VLOAD_32(v4,      0xc28c7596,  0x4288b9ff,  0xc28b8355,  0xc2b90586,  0xc256459e,  0xc2b83240,  0x42b8ade2,  0x4229eda2,  0x42c64f03,  0xc0be5be9,  0xc25fb3b4,  0x426ff986,  0xc2343405,  0xc289de32,  0x425c8eb2,  0xc2a07923);
  asm volatile("vfwmacc.vf v4, %[A], v2, v0.t" :: [A] "f" (dscalar_16));
  //               -70.22966003,  453.72070312, -69.75650787,  781.10052490, -53.56798553,  2207.94091797,  92.33961487, -3046.42993164,  99.15431976, -901.24902344, -55.92549133, -1947.49658203, -45.05080032, -3145.74072266,  55.13935089, -626.49584961
  VCMP_U32(7, v4,  0xc28c7596,  0x43e2dc40,  0xc28b8355,  0x4443466f,  0xc256459e,  0x4509ff0e,  0x42b8ade2,  0xc53e66e1,  0x42c64f03,  0xc4614ff0,  0xc25fb3b4,  0xc4f36fe4,  0xc2343405,  0xc5449bda,  0x425c8eb2,  0xc41c9fbc);

  VSET(16, e32, m1);
  double dscalar_32;
  //               -260866.17187500, -221967.43750000, -907157.25000000,  754760.87500000, -585546.12500000,  260611.84375000, -768453.25000000, -117569.82812500, -469705.78125000,  775094.50000000,  533114.81250000, -798136.87500000,  66693.82812500,  246179.67187500,  728220.87500000, -749270.75000000
  VLOAD_32(v2,      0xc87ec08b,  0xc858c3dc,  0xc95d7954,  0x4938448e,  0xc90ef4a2,  0x487e80f6,  0xc93b9c54,  0xc7e5a0ea,  0xc8e55939,  0x493d3b68,  0x490227ad,  0xc942db8e,  0x478242ea,  0x487068eb,  0x4931c9ce,  0xc936ed6c);
  //                              -164832.20312500
  BOX_FLOAT_IN_DOUBLE(dscalar_32,  0xc820f80d);
  VLOAD_8(v0, 0xAA, 0xAA);
  //               -730249.9193813583115116, -885955.2111547881504521, -739704.0702666083816439,  991252.9466537751723081, -543412.1947198503185064,  859135.3883249030914158,  862259.4763332824222744,  331294.3916525302920491,  936699.0835190876387060, -813722.4244660194963217, -602138.5575914122164249,  253718.7884360067546368,  7255.4825419568223879,  957493.0229552322998643, -446793.8022573012858629, -757660.7323241395642981
  VLOAD_64(v4,      0xc1264913d6b92745,  0xc12b09866c1c7afb,  0xc12692f023f9fc22,  0x412e4029e4afcdba,  0xc120956863b251fa,  0x412a37fec6d2858e,  0x412a5066f3e1f4bc,  0x41143879910d5c64,  0x412c95f62ac3038c,  0xc128d534d9539c30,  0xc12260351d7c9f20,  0x410ef8b64eb78980,  0x40bc577b87dea380,  0x412d386a0bc0c9c8,  0xc11b45273582f020,  0xc1271f3976f3308b);
  asm volatile("vfwmacc.vf v4, %[A], v2, v0.t" :: [A] "f" (dscalar_32));
  //               -730249.9193813583115116,  36586495789.9245910644531250, -739704.0702666083816439, -124407906605.8560791015625000, -543412.1947198503185064, -42956365230.3924331665039062,  862259.4763332824222744,  19379625085.2629890441894531,  936699.0835190876387060, -127761347787.4947814941406250, -602138.5575914122164249,  131558913220.3411712646484375,  7255.4825419568223879, -40577380186.7228927612304688, -446793.8022573012858629,  123503190798.8887634277343750
  VCMP_U64(8, v4,  0xc1264913d6b92745,  0x422109733e5bd964,  0xc12692f023f9fc22,  0xc23cf74a012ddb28,  0xc120956863b251fa,  0xc22400cc3b5cc8ed,  0x412a5066f3e1f4bc,  0x42120c7671f50d4d,  0x412c95f62ac3038c,  0xc23dbf2b74cb7eaa,  0xc12260351d7c9f20,  0x423ea185b4c45757,  0x40bc577b87dea380,  0xc222e5335eb5721f,  0xc11b45273582f020,  0x423cc15d230ee386);
};

int main(void) {
  enable_vec();
  enable_fp();

  TEST_CASE1();
  TEST_CASE2();
  TEST_CASE3();
  TEST_CASE4();

  EXIT_CHECK();
}

